﻿using Basic.FlowApplication.Model.FlowEvent;
using Basic.FlowCollect;
using Basic.FlowModel;
using Basic.FlowModel.DB;
using Basic.FlowModel.Flow;
using Basic.FlowModel.NodeFormPower;
using Basic.FlowModel.NodeRoute;
using Basic.FlowRemoteModel.Flow.Model;
using Basic.FlowService.Interface;
using Basic.FlowService.Model.Relation;
using WeDonekRpc.Client;
using WeDonekRpc.Helper;

namespace Basic.FlowService.Extend
{
    internal class FlowCopyService : IFlowCopyService
    {
        private readonly INodeEventCollect _NodeEvent;
        private readonly IFlowCollect _Flow;
        private readonly IFlowNodeCollect _Node;
        private readonly INodeMsgCollect _NodeMsg;
        private readonly INodeAuditEmpCollect _AuditEmp;
        private readonly INodeRouteCollect _NodeRoute;
        private readonly INodeFormDataRelationCollect _DataRelation;
        private readonly INodeFormPowerCollect _FormPower;

        public FlowCopyService ( INodeEventCollect nodeEvent,
            IFlowCollect flow,
            IFlowNodeCollect node,
            INodeMsgCollect msg,
            INodeAuditEmpCollect auditEmp,
            INodeRouteCollect route,
            INodeFormDataRelationCollect relation,
            INodeFormPowerCollect formPower )
        {
            this._NodeEvent = nodeEvent;
            this._Flow = flow;
            this._Node = node;
            this._NodeMsg = msg;
            this._AuditEmp = auditEmp;
            this._NodeRoute = route;
            this._DataRelation = relation;
            this._FormPower = formPower;
        }
        private string _CreateNewVer ( DBFlowList flow )
        {
            string ver = this._Flow.GetMaxVer(flow.Id);
            if ( ver.IsNull() )
            {
                ver = flow.VerNum;
            }
            int[] t = ver.Remove(0, 1).SplitToInt('.');
            if ( t[2] == 9 && t[1] == 9 )
            {
                t[0] = t[0] + 1;
            }
            else if ( t[2] == 9 )
            {
                t[1] = t[1] + 1;
            }
            else
            {
                t[2] = t[2] + 1;
            }
            return string.Format("v{0}.{1}.{2}", t[0], t[1], t[2]);
        }
        public long Copy ( FlowCopy arg, long empId )
        {
            DBFlowList flow = this._Flow.Get(arg.Id);
            string ver = ConstDic.FlowInitVer;
            if ( arg.IsCreateNew == false )
            {
                ver = this._CreateNewVer(flow);
            }
            if ( this._Flow.CheckIsExists(arg.FlowName, ver) )
            {
                throw new ErrorException("flow.name.repeat");
            }
            DBFlowNode[] nodes = this._Node.Gets<DBFlowNode>(flow.Id);
            FlowBodyAdd add = new FlowBodyAdd
            {
                DefFormId = flow.DefFormId,
                FlowName = arg.FlowName,
                SourceId = arg.IsCreateNew ? null : flow.SourceId.GetValueOrDefault(flow.Id),
                FlowType = arg.FlowType,
                Remark = arg.Remark,
                VerNum = ver,
                CreateBy = empId
            };
            add.Nodes = nodes.ConvertMap<DBFlowNode, NodeAdd>();
            RouteBase[] routes = this._NodeRoute.Gets<RouteBase>(flow.Id);
            FormColPowerDto[] powers = this._FormPower.GetsByFlowId(flow.Id);
            NodeDataRelation[] relations = this._DataRelation.GetsByFlowId<NodeDataRelation>(flow.Id);
            DBFlowNodeAuditEmp[] audits = this._AuditEmp.Gets<DBFlowNodeAuditEmp>(flow.Id);
            DBFlowNodeMsg[] msgs = this._NodeMsg.Gets<DBFlowNodeMsg>(flow.Id);
            NodeEvent[] evs = this._NodeEvent.Gets<NodeEvent>(flow.Id);
            add.Nodes.ForEach(a =>
            {
                a.ToNodeId = routes.Convert(c => c.NodeId == a.Id, c => c.ToNodeId);
                a.Relation = relations.Convert(c => c.NodeId == a.Id, c => new DataRelationAdd
                {
                    FormId = c.FormId,
                    ColId = c.ColId,
                    ToColId = c.ToColId,
                    Keywords = c.Keywords
                });
                a.NodeEvent = evs.Convert(c => c.NodeId == a.Id, c => new NodeEventAdd
                {
                    EventId = c.EventId,
                    EventType = c.EventType
                });
                a.AuditEmp = audits.ConvertFind<DBFlowNodeAuditEmp, NodeAuditEmpAdd>(c => c.NodeId == a.Id);
                a.FormPowers = powers.Convert(c => c.NodeId == a.Id, c => new NodeFormPower
                {
                    ColId = c.ColId,
                    Operate = c.Operate,
                });
                a.Msgs = msgs.ConvertMap<DBFlowNodeMsg, NodeMsgAdd>(c => c.NodeId == a.Id);
            });

            return this._Flow.Save(add);
        }
    }
}
